package com.github.lzm320a99981e.autocoding.domain.condition;

import com.google.common.base.CaseFormat;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * 条件组集合
 */
public class ConditionGroups extends ArrayList<ConditionGroup> {

	private static final long serialVersionUID = 5328644574276283124L;

	/**
     * 将 property -> column
     */
    private Function<String, String> toColumnFunction = property -> CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, property);

    /**
     * com.github.lzm320a99981e.component.basicmodel.condition -> sql
     */
    private Function<Condition, String> toSqlFunction = condition -> {
        String property = condition.getProperty();
        Object value = condition.getValue();
        return "(" + toColumnFunction.apply(property) + " " + condition.getOperator().parseExpression(value) + ")";
    };

    /**
     * 转换为SQL
     *
     * @return
     */
    public String toSql() {
        if (isEmpty()) {
            throw new RuntimeException("条件组为空");
        }
        // 每组
        Map<Conditionable.Join, List<String>> groupSqlsMap = new HashMap<>();
        for (ConditionGroup group : this) {
            final List<Condition> conditions = group.getConditions();

            Map<Conditionable.Join, List<String>> sqlsMap = new HashMap<>();
            for (Condition condition : conditions) {
                Conditionable.Join join = condition.getJoin();
                String sql = toSqlFunction.apply(condition);
                if (!sqlsMap.containsKey(join)) {
                    sqlsMap.put(join, new ArrayList<>());
                }
                sqlsMap.get(join).add(sql);
            }
            // 组装SQL
            String groupSql = "(" + assemblySql(sqlsMap) + ")";

            // 对每组SQL进行合并
            Conditionable.Join join = group.getJoin();
            if (!groupSqlsMap.containsKey(join)) {
                groupSqlsMap.put(join, new ArrayList<>());
            }
            groupSqlsMap.get(join).add(groupSql);

        }
        return assemblySql(groupSqlsMap);
    }

    /**
     * 组装SQL
     *
     * @param sqlsMap
     * @return
     */
    private String assemblySql(Map<Conditionable.Join, List<String>> sqlsMap) {
        StringBuilder groupSql = new StringBuilder();
        if (sqlsMap.containsKey(Conditionable.Join.AND)) {
            groupSql.append("(" + String.join(" AND ", sqlsMap.get(Conditionable.Join.AND)) + ")");
        }
        if (sqlsMap.containsKey(Conditionable.Join.OR)) {
            groupSql.append((groupSql.length() > 0 ? " OR " : "") + String.join(" OR ", sqlsMap.get(Conditionable.Join.OR)));
        }
        return groupSql.toString();
    }

}
